webpack 构建过程
- 初始化参数:将 shell 和 配置文件中的 参数进行合并,得到最终参数
- 初始化 compiler :初始化 Compiler 对象,加载所有配置的插件,注册所有的插件
- 开始编译:开始执行 compire run,
- 确定入口:从入口 entry 开始分析,
- 编译模块:调用所有配置的 Loader 对文件进行编译解析,递归找到模块依赖模块,直到所有入口文件都经过处理
- 输出资源:根据入口和模块的依赖,组装多个包含多个模块的 chunk,把每个 chunk 转化成一个单独文件加入到输出文件列表
- 文件输出:每个 chunk 包装成一个文件并输出
构建过程简易
- 初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
- 编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
- 输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
js
let fs = require("fs");
let path = require("path");
const { SyncHook } = require("tapable");
class Compiler {
constructor(options) {
this.options = options;
this.hooks = {
run: new SyncHook(),
done: new SyncHook(),
};
}
run() {
this.hooks.run.call();
let modules = [];
let chunks = [];
let files = [];
// entry 找到入口
let entry = path.join(this.options.context, this.options.entry);
// 入口分析,调用配置的 loader 进行编译
let entryContent = fs.readFileSync(entry, "utf8");
let entrySource = babelLoader(entryContent);
let entryModule = { id: entry, source: entrySource };
modules.push(entryModule);
//递归找依赖
let title = path.join(this.options.context, "./src/title.js");
let titleContent = fs.readFileSync(title, "utf8");
let titleSource = babelLoader(titleContent);
let titleModule = { id: title, source: titleSource };
modules.push(titleModule);
//根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk
let chunk = { name: "main", modules };
chunks.push(chunk);
//再把每个Chunk转换成一个单独的文件加入到输出列表
let file = {
file: this.options.output.filename,
source: `
(function (modules) {
function __webpack_require__(moduleId) {
var module = { exports: {} };
modules[moduleId].call(
module.exports,
module,
module.exports,
__webpack_require__
);
return module.exports;
}
return __webpack_require__("./src/app.js");
})(
{
"./src/app.js": function (module, exports, __webpack_require__) {
var title = __webpack_require__("./src/title.js");
console.log(title);
},
"./src/title.js": function (module) {
module.exports = "title";
},
});
`,
};
files.push(file);
//在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
let outputPath = path.join(
this.options.output.path,
this.options.output.filename
);
fs.writeFileSync(outputPath, file.source, "utf8");
this.hooks.done.call();
}
}
// 获取参数
let options = require("./webpack.config");
// 初始化 compiler
let compiler = new Compiler(options);
// 加载插件
if (options.plugins && Array.isArray(options.plugins)) {
for (const plugin of options.plugins) {
plugin.apply(compiler);
}
}
// 编译
compiler.run();
function babelLoader(source) {
return `var sum = function sum(a, b) {
return a + b;
};`;
}
webpack 如何指定模块化规范(amd、cmd 这些)
libraryTarget: 'umd'